﻿namespace STLTypeVisualizer
{
	using System;
	using System.Collections.Generic;
	using System.Runtime.InteropServices;
	using VisualGDBExpressions;

	internal abstract class TreeFilter : TypeListBasedExpressionFilter
	{
		protected TreeFilter(params string[] supportedTypes) : base(supportedTypes)
		{
		}

		protected abstract IExpression CreateNodeExpression(IExpressionEvaluator evaluator, string treeNodeExpr, ref int idx);
		protected override IExpression DoAttach(IExpression expr, IExpressionEvaluator evaluator)
		{
			string typeOverride;
			string fullNameForEvaluator = expr.FullNameForEvaluator;
			string type = expr.Type;
			StaticExpressionFilter filter1 = expr as StaticExpressionFilter;
			if (filter1 != null)
			{
				typeOverride = filter1.TypeOverride;
			}
			else
			{
				StaticExpressionFilter local1 = filter1;
				typeOverride = null;
			}
			if (typeOverride != null)
			{
				type = (expr as StaticExpressionFilter).BaseExpression.Type;
			}
			char[] trimChars = new char[] { '&' };
			type = type.TrimEnd(trimChars);
			return Eval(type, fullNameForEvaluator, expr, evaluator);
		}

		protected abstract IExpression Eval(string type, string fullNameForEvaluator, IExpression expr, IExpressionEvaluator evaluator);

		protected abstract string ExpandLabel { get; }

		protected abstract class TreeChildProvider : IExpressionChildProvider
		{
			protected IExpressionEvaluator _Evaluator;
			protected string _ListType;
			protected ulong _RootNodeAddr;
			protected IExpression _ActualMembersNode;
			protected TreeFilter _Filter;
			protected List<IExpression> _Children;

			public TreeChildProvider(IExpressionEvaluator evaluator, string listType, ulong rootNodeAddr, IExpression actualMembersNode, TreeFilter filter)
			{
				this._Evaluator = evaluator;
				this._ListType = listType;
				this._RootNodeAddr = rootNodeAddr;
				this._ActualMembersNode = actualMembersNode;
				this._Filter = filter;
			}

			private void DoAddNodeRecursively(TreeFilter.TreeNode node, ref int idx)
			{
				if (node != null)
				{
					if (node.LeftAddr != 0)
					{
						this.DoAddNodeRecursively(this.QueryNode(node.LeftAddr), ref idx);
					}
					this._Children.Add(this._Filter.CreateNodeExpression(this._Evaluator, node.SelfExpr, ref idx));
					if (node.RightAddr != 0)
					{
						this.DoAddNodeRecursively(this.QueryNode(node.RightAddr), ref idx);
					}
				}
			}

			private void LoadChildren()
			{
				if (this._Children == null)
				{
					List<IExpression> list1 = new List<IExpression>();
					list1.Add(this._ActualMembersNode);
					this._Children = list1;
					TreeFilter.TreeNode node = this.QueryNode(this._RootNodeAddr);
					if (node != null)
					{
						int idx = 0;
						this.DoAddNodeRecursively(node, ref idx);
					}
				}
			}

			public ExpressionChildRange QueryChildren(int firstChild, int childCount)
			{
				ExpressionChildRange range1 = new ExpressionChildRange();
				range1.FirstChildIndex = 0;
				range1.Children = this._Children;
				return range1;
			}

			public int QueryChildrenCount(out ExpressionChildRange additionallyReturnedChildren)
			{
				this.LoadChildren();
				additionallyReturnedChildren = null;
				return ((this._Children == null) ? 0 : this._Children.Count);
			}

			protected abstract TreeFilter.TreeNode QueryNode(ulong addr);

			public bool ChildrenAvailable =>
				true;
		}

		protected class TreeNode
		{
			public string SelfExpr;
			public ulong LeftAddr;
			public ulong RightAddr;
		}
	}
	internal abstract class GccTreeFilter : TreeFilter
	{
		protected GccTreeFilter(params string[] supportedTypes) : base(supportedTypes)
		{
		}

		protected override IExpression Eval(string type, string fullNameForEvaluator, IExpression expr, IExpressionEvaluator evaluator)
		{
			ExpressionValue value2 = evaluator.EvaluateExpression($"(void *)(({fullNameForEvaluator})._M_t._M_impl._M_header._M_parent)", "void *");
			if (!(value2 is ExpressionValue.Integral))
			{
				return null;
			}
			ExpressionValue value3 = evaluator.EvaluateExpression($"(void *)(({fullNameForEvaluator})._M_t._M_impl._M_node_count)", "int");
			string val = !(value3 is ExpressionValue.Integral) ? this.ExpandLabel : $"[{(value3 as ExpressionValue.Integral).Value}个元素]";
			StaticExpressionFilter filter2 = new StaticExpressionFilter(expr);
			filter2.ValueOverride = new ExpressionValue.Custom(val);
			VirtualExpressionNode actualMembersNode = new VirtualExpressionNode("[实际成员]", "", expr.Children);
			actualMembersNode.FixedValue = new ExpressionValue.Composite("{...}");
			filter2.ChildrenOverride = new GccTreeChildProvider(evaluator, type, (value2 as ExpressionValue.Integral).Value, actualMembersNode, this);
			return filter2;
		}

		protected class GccTreeChildProvider : TreeFilter.TreeChildProvider
		{
			public GccTreeChildProvider(IExpressionEvaluator evaluator, string listType, ulong rootNodeAddr, IExpression actualMembersNode, TreeFilter filter) :
				base(evaluator, listType, rootNodeAddr, actualMembersNode, filter)
			{ }

			protected override TreeFilter.TreeNode QueryNode(ulong addr)
			{
				ExpressionValue value2 = this._Evaluator.EvaluateExpression($"(void *)(({this._ListType}::_Rep_type::_Link_type)0x{addr:x})->_M_left", "void *");
				if (!(value2 is ExpressionValue.Integral))
				{
					return null;
				}
				TreeFilter.TreeNode node1 = new TreeFilter.TreeNode();
				node1.LeftAddr = (value2 as ExpressionValue.Integral).Value;
				TreeFilter.TreeNode node = node1;
				value2 = this._Evaluator.EvaluateExpression($"(void *)(({this._ListType}::_Rep_type::_Link_type)0x{addr:x})->_M_right", "void *");
				if (!(value2 is ExpressionValue.Integral))
				{
					return null;
				}
				node.RightAddr = (value2 as ExpressionValue.Integral).Value;
				node.SelfExpr = $"(({this._ListType}::_Rep_type::_Link_type)0x{addr:x})";
				return node;
			}
		}
	}

	internal abstract class ClangTreeFilter : TreeFilter
	{
		protected ClangTreeFilter(params string[] supportedTypes) : base(supportedTypes)
		{
		}

		protected override IExpression Eval(string type, string fullNameForEvaluator, IExpression expr, IExpressionEvaluator evaluator)
		{
			// 由于Clang的__tree数据结构不是在一个节点中表示左右两个节点，而是：
			// __parent_节点下只有一个__left_节点
			// __left_节点下有一个__right_节点和一个__parent_
			// __right_节点下有一个__right_节点和一个__parent_
			// 所以实际有效的根节点是第一个左节点
			ExpressionValue value2 = evaluator.EvaluateExpression($"(void *)(({fullNameForEvaluator}).__tree_.__pair1_.__value_.__left_)", "void *");
			if (!(value2 is ExpressionValue.Integral))
			{
				return null;
			}
			ExpressionValue value3 = evaluator.EvaluateExpression($"(void *)(({fullNameForEvaluator}).__tree_.__pair3_.__value_)", "int");
			string val = !(value3 is ExpressionValue.Integral) ? this.ExpandLabel : $"[{(value3 as ExpressionValue.Integral).Value}个元素]";
			StaticExpressionFilter filter2 = new StaticExpressionFilter(expr);
			filter2.ValueOverride = new ExpressionValue.Custom(val);
			VirtualExpressionNode actualMembersNode = new VirtualExpressionNode("[实际成员]", "", expr.Children);
			actualMembersNode.FixedValue = new ExpressionValue.Composite("{...}");
			filter2.ChildrenOverride = new ClangTreeChildProvider(evaluator, type, (value2 as ExpressionValue.Integral).Value, actualMembersNode, this);
			return filter2;
		}

		protected class ClangTreeChildProvider : TreeFilter.TreeChildProvider
		{
			public ClangTreeChildProvider(IExpressionEvaluator evaluator, string listType, ulong rootNodeAddr, IExpression actualMembersNode, TreeFilter filter) :
				base(evaluator, listType, rootNodeAddr, actualMembersNode, filter)
			{
			}
			protected override TreeFilter.TreeNode QueryNode(ulong addr)
			{
				ExpressionValue value1 = this._Evaluator.EvaluateExpression($"(void *)(({this._ListType}::__base::__node_pointer)0x{addr:x})->__left_", "void *");
				if (!(value1 is ExpressionValue.Integral))
				{
					return null;
				}
				TreeFilter.TreeNode node1 = new TreeFilter.TreeNode();
				node1.LeftAddr = (value1 as ExpressionValue.Integral).Value;
				TreeFilter.TreeNode node = node1;
				ExpressionValue value2 = this._Evaluator.EvaluateExpression($"(void *)(({this._ListType}::__base::__node_pointer)0x{addr:x})->__right_", "void *");
				if (!(value2 is ExpressionValue.Integral))
				{
					return null;
				}
				node.RightAddr = (value2 as ExpressionValue.Integral).Value;
				node.SelfExpr = $"(({this._ListType}::__base::__node_pointer)0x{addr:x})";
				return node;
			}
		}
	}
}

